package frame;

import Beans.*;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MainFrame extends JFrame{
    public static Lock lock1 = new ReentrantLock(true);
    public static Lock lock2 = new ReentrantLock(true);

    public static insertToReady loaddata = new insertToReady(lock1,lock2);
    private static runProcess runProcess=new runProcess(lock1,lock2);
    private static Thread t1 = new Thread(loaddata);
    private static Thread t3 = new Thread(runProcess);
    private static boolean runningStatus = false;
    public static final MainMemory[] mainMemories = StorageMethods.createStorage(50);

    public static JTable newTable;
    private static JScrollPane newTableScrollPane;
    public static JTable readyTable;
    private static JScrollPane readyTableScrollPane;
    public static JTable pendTable;
    private static JScrollPane pendTableScrollPane;
    public static JTable runTable;
    private static JScrollPane runTableScrollPane;
    public static JTable terminatedTable;
    private static JScrollPane terminatedTableScrollPane;
    private static JScrollPane memoryTableScrollPane;
    public static JTable memoryTable;
    public static JButton pendButton;
    public static JButton cancelPendButton;

    static Queue<PCB> newQueue = new LinkedList<PCB>();
    static PCB[] readyQueue = new PCB[6];
    static Queue<PCB> pendQueue = new LinkedList<PCB>();
    static Queue<PCB> runningQueue = new LinkedList<PCB>();
    static Queue<PCB> terminatedQueue = new LinkedList<PCB>();

    private static final String[] columnNames = {"PID", "timeRequired", "priority"};
    private static final String[] terminatedColumnNames = {"PID", "priority", "timeResponse", "timeWait", "timeAll"};
    private static final String[] memoryColumnNames={"Memory","ProcessStored"};

    /**
    * @Description: 创建new队列和ready队列的表格模型
    * @Param: []
    * @return: javax.swing.table.DefaultTableModel
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static DefaultTableModel createNormalTableModel(){
        DefaultTableModel dm=new DefaultTableModel(columnNames,0);
        return dm;
    }

    /**
    * @Description: 创建terminated队列的表格模型
    * @Param: []
    * @return: javax.swing.table.DefaultTableModel
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static DefaultTableModel createTerminatedTableModel(){
        DefaultTableModel dm=new DefaultTableModel(terminatedColumnNames,0);
        return dm;
    }

    /**
    * @Description: 创建主内存的表格模型
    * @Param: []
    * @return: javax.swing.table.DefaultTableModel
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static DefaultTableModel createMemoryTableModel(){
        DefaultTableModel dm = new DefaultTableModel(memoryColumnNames,0);
        return dm;
    }

    /**
    * @Description: 更新new队列表格数据
    * @Param: [newTable, newQueue]
    * @return: void
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static void getNewData(JTable newTable,Queue<PCB> newQueue){
        DefaultTableModel dm = createNormalTableModel();
        for(PCB pcb : newQueue){
            String[] rows = new String[3];
            rows[0] = pcb.getPid();
            rows[1] = String.valueOf(pcb.getTimeRequired());
            rows[2] = String.valueOf(pcb.getPriority());

            dm.addRow(rows);
        }
        newTable.setModel(dm);
    }

    /**
    * @Description: 更新ready队列表格数据
    * @Param: [readyTable, readyQueue]
    * @return: void
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static void getReadyData(JTable readyTable,PCB[] readyQueue){
        DefaultTableModel dm = createNormalTableModel();
        for(PCB pcb : readyQueue){
            String[] rows = new String[3];
            if(pcb!=null) {
                rows[0] = pcb.getPid();
                rows[1] = String.valueOf(pcb.getTimeRequired());
                rows[2] = String.valueOf(pcb.getPriority());
            }

            dm.addRow(rows);
        }
        readyTable.setModel(dm);
    }

    /**
    * @Description: 更新running队列表格数据
    * @Param: [runTable, runQueue]
    * @return: void
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static void getRunData(JTable runTable, Queue<PCB> runQueue){
        DefaultTableModel dm = createNormalTableModel();
        for(PCB pcb: runQueue){
            String[] rows = new String[3];
            if(pcb!=null) {
                rows[0] = pcb.getPid();
                rows[1] = String.valueOf(pcb.getTimeRequired());
                rows[2] = String.valueOf(pcb.getPriority());

                dm.addRow(rows);
            }
        }
        runTable.setModel(dm);
    }

    /**
    * @Description: 更新主内存表格数据
    * @Param: [memoryTable, mainMemories]
    * @return: void
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static void getMemoryData(JTable memoryTable,MainMemory[] mainMemories){
        DefaultTableModel dm = createMemoryTableModel();
        for(int i = 0;i<mainMemories.length;i++){
            String[] rows = new String[2];
            rows[0] = String.valueOf(i+1);
            if(mainMemories[i].getProcessStored()!=null) {
                rows[1] = mainMemories[i].getProcessStored().getPid();
            }
            else{
                rows[1] = "";
            }
            dm.addRow(rows);
        }
        memoryTable.setModel(dm);
    }

    /**
    * @Description: 更新terminated队列表格数据
    * @Param: [terminatedTable, terminatedQueue]
    * @return: void
    * @Author: PY
    * @Date: 2021/11/26
    */
    public static void getTerminatedData(JTable terminatedTable,Queue<PCB> terminatedQueue){
        DefaultTableModel dm = createTerminatedTableModel();
        for (PCB pcb : terminatedQueue){
            String[] rows = new String[5];
            rows[0] = pcb.getPid();
            rows[1] = String.valueOf(pcb.getTimeRequired());
            rows[2] = String.valueOf(pcb.getPriority());
            rows[3] = String.valueOf(pcb.getTimeWait());
            rows[4] = String.valueOf(pcb.getTimeRequired()+pcb.getTimeWait());

            dm.addRow(rows);
        }
        terminatedTable.setModel(dm);
    }



    public MainFrame(){
        final int[] count = {0};

        setTitle("CPU调度模拟");
        setBounds(0,0,1380,660);
        getContentPane().setLayout(null);

        SchedulingMethods.insertNewFromDB(newQueue);



        int x1 = 20;
        int y1 = 20;
        JLabel newlabel = new JLabel("NEW");
        newlabel.setBounds(x1,y1,300,15);
        getContentPane().add(newlabel);
        y1 += 15;
        newTableScrollPane = new JScrollPane();
        newTableScrollPane.setBounds(x1,y1,300,250);
        getContentPane().add(newTableScrollPane);

        x1 +=310;
        y1 -=15;
        JLabel readylabel = new JLabel("READY");
        readylabel.setBounds(x1,y1,300,15);
        getContentPane().add(readylabel);
        y1 +=15;
        readyTableScrollPane = new JScrollPane();
        readyTableScrollPane.setBounds(x1,y1,300,250);
        getContentPane().add(readyTableScrollPane);

        x1 +=310;
        pendButton = new JButton("挂起");
        pendButton.setBounds(x1,y1,100,30);
        getContentPane().add(pendButton);
        pendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int[] indexs = readyTable.getSelectedRows();
                if(indexs.length!=0){
                    String Pid = (String) readyTable.getValueAt(indexs[0],0);
                    SchedulingMethods.suspend(Pid,pendQueue,readyQueue,newQueue);
                    getRunData(pendTable,pendQueue);
                    getReadyData(readyTable,readyQueue);
                }
            }
        });

        y1 += 40;
        cancelPendButton = new JButton("解挂");
        cancelPendButton.setBounds(x1,y1,100,30);
        getContentPane().add(cancelPendButton);
        cancelPendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int[] indexs = pendTable.getSelectedRows();
                if(indexs.length!=0){
                    String Pid = (String) pendTable.getValueAt(indexs[0],0);
                    SchedulingMethods.suspendCancel(Pid,pendQueue,newQueue);
                    getRunData(pendTable,pendQueue);
                    getReadyData(readyTable,readyQueue);
                    getNewData(newTable,newQueue);
                }
            }
        });

        y1 -= 65;
        x1 += 110;
        JLabel pendlabel=new JLabel("PEND");
        pendlabel.setBounds(x1,y1,300,30);
        getContentPane().add(pendlabel);
        y1 +=25;
        pendTableScrollPane = new JScrollPane();
        pendTableScrollPane.setBounds(x1,y1,300,250);
        getContentPane().add(pendTableScrollPane);

        y1 += 260;
        int x2 = 20;

        JLabel runlabel=new JLabel("RUNNING");
        runlabel.setBounds(x2,y1,300,30);
        getContentPane().add(runlabel);
        y1+=30;
        runTableScrollPane = new JScrollPane();
        runTableScrollPane.setBounds(x2,y1,300,250);
        getContentPane().add(runTableScrollPane);

        x2 += 310;
        y1 -= 30;
        JLabel terminatedlabel = new JLabel("TERMINATED");
        terminatedlabel.setBounds(x2,y1,300,30);
        getContentPane().add(terminatedlabel);
        y1 += 30;
        terminatedTableScrollPane = new JScrollPane();
        terminatedTableScrollPane.setBounds(x2,y1,300,250);
        getContentPane().add(terminatedTableScrollPane);

        x2 += 310;
        y1 += 220;
        JButton runButton = new JButton("开始运行");
        runButton.setBounds(x2,y1,100,30);
        getContentPane().add(runButton);
        runButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                t1.start();
                t3.start();
            }
        });

        x2 += 110;
        y1 -= 220;
        JLabel addLabel = new JLabel("ADD");
        addLabel.setBounds(x2,y1,300,30);
        getContentPane().add(addLabel);
        y1 += 30;
        JLabel timeRequiredlabel = new JLabel("timeRequired:");
        timeRequiredlabel.setBounds(x2,y1,100,30);
        getContentPane().add(timeRequiredlabel);
        JTextField timeRequiredText = new JTextField();
        x2 += 100;
        timeRequiredText.setBounds(x2,y1,200,30);
        getContentPane().add(timeRequiredText);

        y1 += 30;
        x2 -=100;
        JLabel prioritylabel = new JLabel("Priority:");
        prioritylabel.setBounds(x2,y1,100,30);
        getContentPane().add(prioritylabel);
        JTextField priorityText = new JTextField();
        x2 += 100;
        priorityText.setBounds(x2,y1,200,30);
        getContentPane().add(priorityText);

        y1 += 30;
        x2 -=100;
        JLabel Memorylabel = new JLabel("MemoryRequired:");
        Memorylabel.setBounds(x2,y1,100,30);
        getContentPane().add(Memorylabel);
        JTextField memoryText = new JTextField();
        x2 += 100;
        memoryText.setBounds(x2,y1,200,30);
        getContentPane().add(memoryText);

        y1 += 60;
        x2 -= 100;
        JButton addButton = new JButton("添加进程");
        addButton.setBounds(x2,y1,100,30);
        getContentPane().add(addButton);
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if((!priorityText.getText().equals(""))&&(!timeRequiredText.getText().equals(""))) {
                    SchedulingMethods.addProcess(Integer.parseInt(priorityText.getText()), Integer.parseInt(timeRequiredText.getText()),Integer.parseInt(memoryText.getText()), newQueue);
                    getNewData(newTable, newQueue);
                }
            }
        });

        y1 = 20;
        x2 +=310;
        JLabel memoryLabel = new JLabel("Memory");
        memoryLabel.setBounds(x2,y1,300,15);
        getContentPane().add(memoryLabel);
        y1 += 20;
        memoryTableScrollPane = new JScrollPane();
        memoryTableScrollPane.setBounds(x2,y1,300,500);
        getContentPane().add(memoryTableScrollPane);

        newTable = new JTable();
        readyTable = new JTable();
        runTable = new JTable();
        pendTable = new JTable();
        terminatedTable = new JTable();
        memoryTable = new JTable();

        newTableScrollPane.setViewportView(newTable);
        readyTableScrollPane.setViewportView(readyTable);
        pendTableScrollPane.setViewportView(pendTable);
        runTableScrollPane.setViewportView(runTable);
        terminatedTableScrollPane.setViewportView(terminatedTable);
        memoryTableScrollPane.setViewportView(memoryTable);

        newTable.setFillsViewportHeight(true);
        readyTable.setFillsViewportHeight(true);
        pendTable.setFillsViewportHeight(true);
        runTable.setFillsViewportHeight(true);
        terminatedTable.setFillsViewportHeight(true);
        memoryTable.setFillsViewportHeight(true);

        newTable.setModel(createNormalTableModel());
        runTable.setModel(createNormalTableModel());
        readyTable.setModel(createNormalTableModel());
        pendTable.setModel(createNormalTableModel());
        terminatedTable.setModel(createTerminatedTableModel());
        memoryTable.setModel(createMemoryTableModel());
    }
}

class runProcess implements Runnable{  //用于模拟进程运行的线程
    Lock firstLock;
    Lock secondLock;
    runProcess(Lock lock1,Lock lock2){
        firstLock = lock1;
        secondLock = lock2;
    }
    public void run(){
        while(true) {
            firstLock.lock();
            if (MainFrame.readyQueue[0] != null && MainFrame.runningQueue.isEmpty()) {  //当ready队列不为空且running队列为空时运行
                MainFrame.getNewData(MainFrame.newTable, MainFrame.newQueue);
                SchedulingMethods.insertToRunning(MainFrame.readyQueue, MainFrame.runningQueue);
                MainFrame.getReadyData(MainFrame.readyTable, MainFrame.readyQueue);
                MainFrame.getRunData(MainFrame.runTable, MainFrame.runningQueue);
                SchedulingMethods.runProcess(MainFrame.runningQueue, MainFrame.terminatedQueue, MainFrame.readyQueue);
                MainFrame.getRunData(MainFrame.runTable, MainFrame.runningQueue);
                MainFrame.getTerminatedData(MainFrame.terminatedTable, MainFrame.terminatedQueue);
            }
            firstLock.unlock();  //当运行完毕后立刻唤醒添加进程的线程
        }
    }
}
